#include "gbBook/gbJournal.h"

#include <string.h>

#include "gbBook/gbBook.h"
#include "glib-object.h"

G_DEFINE_TYPE(GBJournal, gb_journal, GB_TYPE_BOOK);

#define GB_JOURNAL_GET_PRIVATE(OBJ) G_TYPE_INSTANCE_GET_PRIVATE(OBJ, GB_TYPE_JOURNAL, GBJournalPrivate)

typedef struct _GBJournalPrivate {
    guint    pages;
    GString *description;
} GBJournalPrivate;

typedef enum {
    PROP_JOURNAL_0,
    PROP_JOURNAL_DESC,  // Begin GB_BOOK_PROPERTY N_PROPERTYS
    PROP_JOURNAL_PAGES,
    N_PROPERTYS
} GB_JOURNAL_PROPERTY;

static void gb_journal_get_property(GObject *obj, guint prop_id, GValue *value, GParamSpec *pspec) {
    GBJournal        *self = GB_JOURNAL(obj);
    GBJournalPrivate *priv = GB_JOURNAL_GET_PRIVATE(self);
    switch (prop_id) {
        case PROP_JOURNAL_DESC:
            g_value_set_string(value, priv->description->str);
            break;
        case PROP_JOURNAL_PAGES:
            g_value_set_uint(value, priv->pages);
            break;
        default:
            G_OBJECT_CLASS(gb_journal_parent_class)->get_property(obj, prop_id, value, pspec);
            break;
    }
}

static void gb_journal_set_property(GObject *obj, guint prop_id, const GValue *value, GParamSpec *pspec) {
    GBJournal        *self = GB_JOURNAL(obj);
    GBJournalPrivate *priv = GB_JOURNAL_GET_PRIVATE(self);
    switch (prop_id) {
        case PROP_JOURNAL_DESC:
            if (priv->description)
                g_string_free(priv->description, TRUE);
            priv->description = g_string_new(g_value_get_string(value));
            break;
        case PROP_JOURNAL_PAGES:
            priv->pages = g_value_get_uint(value);
            break;
        default:
            G_OBJECT_CLASS(gb_journal_parent_class)->set_property(obj, prop_id, value, pspec);
            break;
    }
}

static void gb_journal_class_init(GBJournalClass *klass) {
    g_type_class_add_private(klass, sizeof(GBJournalPrivate));

    GObjectClass *base_class = G_OBJECT_CLASS(klass);
    base_class->set_property = gb_journal_set_property;
    base_class->get_property = gb_journal_get_property;

    // TEST
    // guint        cnt;
    // GParamSpec **base_props = g_object_class_list_properties(base_class, &cnt);
    // g_print("scan props count: %d\n", cnt);
    // for (int i = 0; i < cnt; ++i) {
    //     g_print("%d. Get Base %s ParamSpec. Param ID %d\n", i, base_props[i]->name, base_props[i]->param_id);
    // }

    GParamSpec *props[N_PROPERTYS] = {
        NULL,
    };
    props[PROP_JOURNAL_DESC] =
        g_param_spec_string("desc", "Description", "Journal Description", "UNKNOW", G_PARAM_READWRITE);
    props[PROP_JOURNAL_PAGES] =
        g_param_spec_uint("pages", "Pages", "Journal Pages", 0, G_MAXUINT, 0, G_PARAM_READWRITE);
    g_object_class_install_properties(base_class, G_N_ELEMENTS(props), props);
}

static void gb_journal_init(GBJournal *self) {
}

void gb_journal_info_print(GBJournal *journal) {
    gb_book_info_print(&journal->parent);

    gchar *desc  = NULL;
    guint  pages = 0;

    g_object_get(G_OBJECT(journal), "desc", &desc, "pages", &pages, NULL);

    g_print("   Description: %s\n"
            "   Pages: %d\n",
            desc,
            pages);
}